#pragma once
#include <iostream>
#include <vector>
#include <functional>
#include <memory>
#include "ip_net_address.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"
// OS
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>

using task_t = std::function<void()>;

class Route // 路线/途径
{

public:
    Route()
    {
        pthread_mutex_init(&_mutex, nullptr);
    }

    void Offline(InetAdress &who) // 让指定用户下线
    {
        // LockGuard lock(&_mutex);
        auto it1 = _online.begin();
        for (; it1 < _online.end(); it1++)
        {
            if (*it1 == who)
            {
                _online.erase(it1);
                LOG(INFO, "%s Offline", who.Str().c_str());
                break;
            }
        }
    }

    void CheckOnlineUser(InetAdress &who) // 先确认在线用户列表有没有这个用户，没有就添加
    {
        // LockGuard lock(&_mutex);
        for (auto name : _online)
        {
            if (who == name)
            {
                return;
            }
        }
        LOG(INFO, "在线用户列表没有这个用户，没有就添加");
        _online.emplace_back(who);
        LOG(INFO, "%d", _online.size());
    }

    void ForwardHelper(int sockfd, std::string message)
    {
        LockGuard lock(&_mutex);
        for (auto name : _online) // 转发给所有用户
        {
            struct sockaddr_in socket = name.Socket(); // 所有用户的socket对象
            int len = sizeof(socket);
            int re = sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&socket, len);
            if (re >= 0)
            {
                LOG(INFO, "a forward success");
            }
            else
            {
                LOG(FATAL, "a forward fail");
                exit(-1);
            }
        }
    }

    void Forward(int sockfd, std::string message, InetAdress who) // 转发
    {
        // 1.检查
        CheckOnlineUser(who);
        // 检查想退出的用户
        if (message == "QUIT" || message == "Q")
        {
            Offline(who);
        }
        // 2.转发
        task_t t = std::bind(&Route::ForwardHelper, this, sockfd, message); // 线程池中的任务
        _tp = ThreadPool<task_t>::GetInstance(5);                           // 生成单例类的函数；
        _tp->Enqueue(&t);                                                   // 推送一个任务
        std::cout << _tp->TaskCount() << std::endl;
    }

    ~Route()
    {
        _tp->Stop();
        _tp->Join();
        pthread_mutex_destroy(&_mutex);
    }

private:
    std::vector<InetAdress> _online; // 在线用户列表
    // InetAdress _user;

    // 添加多次任务时 sockfd message有多个，但都是在同一个类对象中完成的，
    // 连续添加多个任务时 _sockfd _message可能会被覆盖，所以还是用局部变量好
    //  int _sockfd;
    //  std::string _message;

    ThreadPool<task_t> *_tp;
    pthread_mutex_t _mutex;
};